package org.springframework.aop.framework;

import org.springframework.aop.AdvisedSupport;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;
import java.util.List;

/**
 * @Name CglibAopProxy
 * @Description: CGLIB 动态代理 [实现] 类
 * @Version v1.0.0
 * @Author: lichao
 * @Date: 2024-03-27 16:36:43
 **/
public class CglibDynamicAopProxy implements AopProxy {
    private final AdvisedSupport advised;

    public CglibDynamicAopProxy(AdvisedSupport advised) {
        this.advised = advised;
    }

    @Override
    public Object getProxy() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(advised.getTargetSource().getTarget().getClass());
        enhancer.setInterfaces(advised.getTargetSource().getTargetClass());
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                Object result = null;
                // 获取目标对象
                Object target = advised.getTargetSource().getTarget();
                Class<?> targetClass = target.getClass();
                // 获取拦截器链
                List<Object> chain = advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
                CglibMethodInvocation methodInvocation = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy);
                if (chain == null || chain.isEmpty()) {
                    result = methodProxy.invoke(target, args);
                } else {
                    // 执行拦截器链
                    result = methodInvocation.proceed();
                }
                return result;
            }
        });
        return enhancer.create();
    }

    private static class CglibMethodInvocation extends ReflectiveMethodInvocation {
        private final MethodProxy methodProxy;

        public CglibMethodInvocation(Object proxy, Object target, Method method, Object[] arguments, Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatches, MethodProxy methodProxy) {
            super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatches);
            this.methodProxy = methodProxy;
        }

        @Override
        public Object proceed() throws Throwable {
            return super.proceed();
        }
    }


}

